import { sequelize, buildOrder, buildWhere } from "../lib/database.js";
import logger from "../lib/log4js.js";
export class BaseDataMapper {
    /***
     * @param name model name
     */

    constructor(name) {
        if (!name) throw new Error("model name cant be null");
        this.name = name;
        this.model = sequelize.modelManager.getModel(name);
    }
    getName() {
        return this.name;
    }
    async save({ values }, options) {
        if (!values || Object.keys(values).length === 0) throw new Error("[save]:values can not be null ")
        logger.debug(`mapper:[save], ${values}`);
        const result = await this.model.create({ ...values }, { ...options });
        return result;
    }
    async saveBatch({ records }, options) {
        if (!records || Object.keys(records).length === 0) throw new Error("[saveBatch]:records can not be null ")
        return await this.model.bulkCreate(records, { ...options, ignoreDuplicates: true });
    }
    async update({ values, where }, options) {
        const whval = buildWhere(where);
        if (!values
            || !whval
            || Object.keys(values).length === 0
        ) throw new Error("[update]:nether values or where can not be null ")
        return await this.model.update(values, { ...options, where: whval });
    }
    async saveOrUpdate({ values }, options) {
        logger.debug(`mapper:[saveOrUpdate]: ${JSON.stringify(values)}`);
        if (!values || Object.keys(values).length === 0) throw new Error("[saveOrUpdate]:values can not be null ")
        return await this.model.upsert(values, { ...options });
    }
    async remove({ where }, options) {
        const whval = buildWhere(where);
        if (!whval) throw new Error("[remove]:where can not be null ")
        logger.debug(`[remove:where],${JSON.stringify(whval)}`)
        const result = await this.model.destroy({
            ...options,
            where: whval
        })
        return result;
    }

    /***
     * @description find data by pager of query
     * @param {number} [page=1] 
     * @param {number} [offset=10] 
     * @param {*} where 
     * @param {*} order 
     * @returns {pager}
     * 
     */
    async findPager({ page = 1, offset = 10, where, order }) {

        const ord = buildOrder(order)
        const wh = buildWhere(where);
        const options = {
            offset: (page - 1) * offset,
            limit: parseInt(offset),
        }
        if (wh) {
            options.where = wh;
        }
        if (ord != null) {
            options.order = ord;
        }
        logger.debug(options)
        const records = await this.model.findAndCountAll(options);
        return { ...records, page: parseInt(page), offset: parseInt(offset) };
    }

    async findList({ where, order = [[]] }) {
        const wh = buildWhere(where);
        const ord = buildOrder(order)
        const options = {

        }
        if (wh) {
            options.where = wh;
        }
        logger.debug(`[mapper:findList] order ${ord}`);
        if (ord) {
            options.order = ord;
        }

        return await this.model.findAll(options);
    }

    async findOne({ pk }) {
        if (!pk || !Object.keys(pk) || Object.keys(pk).length === 0) throw new Error("[findOne]:pk can not be null ")
        const result = await this.model.findByPk(pk);
        return result;
    }

    async findOneByQuery({ where }) {
        const wh = buildWhere(where);
        const options = {
            offset: 0,
            limit: 1,
        }
        if (wh) options.where = wh;
        const result = await this.model.findOne(options);
        return result;
    }
    async removeByQuery({ where }) {
        const wh = buildWhere(where);
        if (wh) {
            const result = await this.model.destroy({ where });
            return result;
        }
        return null;

    }



}